home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / cdrtools-1.10 / libhfs_iso / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-05  |  9.6 KB  |  469 lines

  1. /*
  2.  * hfsutils - tools for reading and writing Macintosh HFS volumes
  3.  * Copyright (C) 1996, 1997 Robert Leslie
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. #include <mconfig.h>
  21. #include <strdefs.h>
  22. #include <errno.h>
  23.  
  24. #include "internal.h"
  25. #include "data.h"
  26. #include "block.h"
  27. #include "file.h"
  28. #include "btree.h"
  29. #include "record.h"
  30. #include "volume.h"
  31.  
  32. /* #include <stdio.h> */
  33.  
  34.  
  35. /*
  36.  * NAME:    file->selectfork()
  37.  * DESCRIPTION:    choose a fork for file operations
  38.  */
  39. void f_selectfork(file, ffork)
  40.     hfsfile    *file;
  41.     int    ffork;
  42. {
  43.   if (ffork == 0)
  44.     {
  45.       file->fork = fkData;
  46.       memcpy(file->ext, file->cat.u.fil.filExtRec, sizeof(ExtDataRec));
  47.     }
  48.   else
  49.     {
  50.       file->fork = fkRsrc;
  51.       memcpy(file->ext, file->cat.u.fil.filRExtRec, sizeof(ExtDataRec));
  52.     }
  53.  
  54.   file->fabn = 0;
  55.   file->pos  = 0;
  56. }
  57.  
  58. /*
  59.  * NAME:    file->getptrs()
  60.  * DESCRIPTION:    make pointers to the current fork's lengths and extents
  61.  */
  62. void f_getptrs(file, lglen, pylen, extrec)
  63.     hfsfile        *file;
  64.     unsigned long    **lglen;
  65.     unsigned long    **pylen;
  66.     ExtDataRec     **extrec;
  67. {
  68.   if (file->fork == fkData)
  69.     {
  70.       if (lglen)
  71.     *lglen  = &file->cat.u.fil.filLgLen;
  72.       if (pylen)
  73.     *pylen  = &file->cat.u.fil.filPyLen;
  74.       if (extrec)
  75.     *extrec = &file->cat.u.fil.filExtRec;
  76.     }
  77.   else
  78.     {
  79.       if (lglen)
  80.     *lglen  = &file->cat.u.fil.filRLgLen;
  81.       if (pylen)
  82.     *pylen  = &file->cat.u.fil.filRPyLen;
  83.       if (extrec)
  84.     *extrec = &file->cat.u.fil.filRExtRec;
  85.     }
  86. }
  87.  
  88. /*
  89.  * NAME:    file->doblock()
  90.  * DESCRIPTION:    read or write a numbered block from a file
  91.  */
  92. int f_doblock(file, number, bp, func)
  93.     hfsfile        *file;
  94.     unsigned long    number;
  95.     block        *bp;
  96.     int         (*func) __PR((hfsvol *, unsigned int, unsigned int, block *));
  97. {
  98.   unsigned int abnum;
  99.   unsigned int blnum;
  100.   unsigned int fabn;
  101.   int i;
  102.  
  103.   abnum = number / file->vol->lpa;
  104.   blnum = number % file->vol->lpa;
  105.  
  106.   /* locate the appropriate extent record */
  107.  
  108.   fabn = file->fabn;
  109.  
  110.   if (abnum < fabn)
  111.     {
  112.       ExtDataRec *extrec;
  113.  
  114.       f_getptrs(file, 0, 0, &extrec);
  115.  
  116.       fabn = file->fabn = 0;
  117.       memcpy(file->ext, extrec, sizeof(ExtDataRec));
  118.     }
  119.   else
  120.     abnum -= fabn;
  121.  
  122.   while (1)
  123.     {
  124.       unsigned int num;
  125.  
  126.       for (i = 0; i < 3; ++i)
  127.     {
  128.       num = file->ext[i].xdrNumABlks;
  129.  
  130. #ifdef APPLE_HYB
  131.       if (i > 0) {
  132. /*        SHOULD NOT HAPPEN! - all the files should not be fragmented
  133.         if this happens, then a serious problem has occured, may be
  134.         a hard linked file? */
  135. #ifdef DEBUG
  136.         fprintf(stderr,"file: %s %d\n",file->name, i); */
  137. #endif /* DEBUG */
  138.         ERROR(HCE_ERROR, "Possible Catalog file overflow - please report error");
  139.         return -1; 
  140.       }
  141. #endif /* APPLE_HYB */
  142.       if (abnum < num)
  143.         return func(file->vol, file->ext[i].xdrStABN + abnum, blnum, bp);
  144.  
  145.       fabn  += num;
  146.       abnum -= num;
  147.     }
  148.  
  149.       if (v_extsearch(file, fabn, &file->ext, 0) <= 0)
  150.     return -1;
  151.  
  152.       file->fabn = fabn;
  153.     }
  154. }
  155.  
  156. /*
  157.  * NAME:    file->alloc()
  158.  * DESCRIPTION:    reserve disk blocks for a file
  159.  */
  160. int f_alloc(file)
  161.     hfsfile    *file;
  162. {
  163.   hfsvol *vol = file->vol;
  164.   ExtDescriptor blocks;
  165.   ExtDataRec *extrec;
  166.   unsigned long *pylen, clumpsz;
  167.   unsigned int start, end;
  168.   node n;
  169.   int i;
  170.  
  171.   clumpsz = file->clump;
  172.   if (clumpsz == 0)
  173.     clumpsz = vol->mdb.drClpSiz;
  174.  
  175.   blocks.xdrNumABlks = clumpsz / vol->mdb.drAlBlkSiz;
  176.  
  177.   if (v_allocblocks(vol, &blocks) < 0)
  178.     return -1;
  179.  
  180.   /* update the file's extents */
  181.  
  182.   f_getptrs(file, 0, &pylen, &extrec);
  183.  
  184.   start  = file->fabn;
  185.   end    = *pylen / vol->mdb.drAlBlkSiz;
  186.  
  187.   n.nnum = 0;
  188.   i      = -1;
  189.  
  190.   while (start < end)
  191.     {
  192.       for (i = 0; i < 3; ++i)
  193.     {
  194.       unsigned int num;
  195.  
  196.       num    = file->ext[i].xdrNumABlks;
  197.       start += num;
  198.  
  199.       if (start == end)
  200.         break;
  201.       else if (start > end)
  202.         {
  203.           v_freeblocks(vol, &blocks);
  204.           ERROR(EIO, "file extents exceed file physical length");
  205.           return -1;
  206.         }
  207.       else if (num == 0)
  208.         {
  209.           v_freeblocks(vol, &blocks);
  210.           ERROR(EIO, "empty file extent");
  211.           return -1;
  212.         }
  213.     }
  214.  
  215.       if (start == end)
  216.     break;
  217.  
  218.       if (v_extsearch(file, start, &file->ext, &n) <= 0)
  219.     {
  220.       v_freeblocks(vol, &blocks);
  221.       return -1;
  222.     }
  223.  
  224.       file->fabn = start;
  225.     }
  226.  
  227.   if (i >= 0 &&
  228.       file->ext[i].xdrStABN + file->ext[i].xdrNumABlks == blocks.xdrStABN)
  229.     file->ext[i].xdrNumABlks += blocks.xdrNumABlks;
  230.   else
  231.     {
  232.       /* create a new extent descriptor */
  233.  
  234.       if (++i < 3)
  235.     file->ext[i] = blocks;
  236.       else
  237.     {
  238.       ExtKeyRec key;
  239.       unsigned char record[HFS_EXTRECMAXLEN];
  240.       int reclen;
  241.  
  242.       /* record is full; create a new one */
  243.  
  244.       file->ext[0] = blocks;
  245.  
  246.       for (i = 1; i < 3; ++i)
  247.         {
  248.           file->ext[i].xdrStABN    = 0;
  249.           file->ext[i].xdrNumABlks = 0;
  250.         }
  251.  
  252.       file->fabn = start;
  253.  
  254.       r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, end);
  255.       r_packextkey(&key, record, &reclen);
  256.       r_packextdata(&file->ext, HFS_RECDATA(record), &reclen);
  257.  
  258.       if (bt_insert(&vol->ext, record, reclen) < 0)
  259.         {
  260.           v_freeblocks(vol, &blocks);
  261.           return -1;
  262.         }
  263.  
  264.       i = -1;
  265.     }
  266.     }
  267.  
  268.   if (i >= 0)
  269.     {
  270.       /* store the modified extent record */
  271.  
  272.       if (file->fabn)
  273.     {
  274.       if ((n.nnum == 0 &&
  275.            v_extsearch(file, file->fabn, 0, &n) <= 0) ||
  276.           v_putextrec(&file->ext, &n) < 0)
  277.         {
  278.           v_freeblocks(vol, &blocks);
  279.           return -1;
  280.         }
  281.     }
  282.       else
  283.     memcpy(extrec, file->ext, sizeof(ExtDataRec));
  284.     }
  285.  
  286.   *pylen += blocks.xdrNumABlks * vol->mdb.drAlBlkSiz;
  287.  
  288.   file->flags |= HFS_UPDATE_CATREC;
  289.  
  290.   return blocks.xdrNumABlks;
  291. }
  292.  
  293. /*
  294.  * NAME:    file->trunc()
  295.  * DESCRIPTION:    release disk blocks unneeded by a file
  296.  */
  297. int f_trunc(file)
  298.     hfsfile    *file;
  299. {
  300.   ExtDataRec *extrec;
  301.   unsigned long *lglen, *pylen, alblksz, newpylen;
  302.   unsigned int dlen, start, end;
  303.   node n;
  304.   int i;
  305.  
  306.   f_getptrs(file, &lglen, &pylen, &extrec);
  307.  
  308.   alblksz  = file->vol->mdb.drAlBlkSiz;
  309.   newpylen = (*lglen / alblksz + (*lglen % alblksz != 0)) * alblksz;
  310.  
  311.   if (newpylen > *pylen)
  312.     {
  313.       ERROR(EIO, "file size exceeds physical length");
  314.       return -1;
  315.     }
  316.   else if (newpylen == *pylen)
  317.     return 0;
  318.  
  319.   dlen  = (*pylen - newpylen) / alblksz;
  320.  
  321.   start = file->fabn;
  322.   end   = newpylen / alblksz;
  323.  
  324.   if (start >= end)
  325.     {
  326.       start = file->fabn = 0;
  327.       memcpy(file->ext, extrec, sizeof(ExtDataRec));
  328.     }
  329.  
  330.   n.nnum = 0;
  331.   i      = -1;
  332.  
  333.   while (start < end)
  334.     {
  335.       for (i = 0; i < 3; ++i)
  336.     {
  337.       unsigned int num;
  338.  
  339.       num    = file->ext[i].xdrNumABlks;
  340.       start += num;
  341.  
  342.       if (start >= end)
  343.         break;
  344.       else if (num == 0)
  345.         {
  346.           ERROR(EIO, "empty file extent");
  347.           return -1;
  348.         }
  349.     }
  350.  
  351.       if (start >= end)
  352.     break;
  353.  
  354.       if (v_extsearch(file, start, &file->ext, &n) <= 0)
  355.     return -1;
  356.  
  357.       file->fabn = start;
  358.     }
  359.  
  360.   if (start > end)
  361.     {
  362.       ExtDescriptor blocks;
  363.  
  364.       file->ext[i].xdrNumABlks -= start - end;
  365.       dlen -= start - end;
  366.  
  367.       blocks.xdrStABN    = file->ext[i].xdrStABN + file->ext[i].xdrNumABlks;
  368.       blocks.xdrNumABlks = start - end;
  369.  
  370.       v_freeblocks(file->vol, &blocks);
  371.     }
  372.  
  373.   *pylen = newpylen;
  374.  
  375.   file->flags |= HFS_UPDATE_CATREC;
  376.  
  377.   do
  378.     {
  379.       while (dlen && ++i < 3)
  380.     {
  381.       unsigned int num;
  382.  
  383.       num    = file->ext[i].xdrNumABlks;
  384.       start += num;
  385.  
  386.       if (num == 0)
  387.         {
  388.           ERROR(EIO, "empty file extent");
  389.           return -1;
  390.         }
  391.       else if (num > dlen)
  392.         {
  393.           ERROR(EIO, "file extents exceed physical size");
  394.           return -1;
  395.         }
  396.  
  397.       dlen -= num;
  398.       v_freeblocks(file->vol, &file->ext[i]);
  399.  
  400.       file->ext[i].xdrStABN    = 0;
  401.       file->ext[i].xdrNumABlks = 0;
  402.     }
  403.  
  404.       if (file->fabn)
  405.     {
  406.       if (n.nnum == 0 &&
  407.           v_extsearch(file, file->fabn, 0, &n) <= 0)
  408.         return -1;
  409.  
  410.       if (file->ext[0].xdrNumABlks)
  411.         {
  412.           if (v_putextrec(&file->ext, &n) < 0)
  413.         return -1;
  414.         }
  415.       else
  416.         {
  417.           if (bt_delete(&file->vol->ext, HFS_NODEREC(n, n.rnum)) < 0)
  418.         return -1;
  419.  
  420.           n.nnum = 0;
  421.         }
  422.     }
  423.       else
  424.     memcpy(extrec, file->ext, sizeof(ExtDataRec));
  425.  
  426.       if (dlen)
  427.     {
  428.       if (v_extsearch(file, start, &file->ext, &n) <= 0)
  429.         return -1;
  430.  
  431.       file->fabn = start;
  432.       i = -1;
  433.     }
  434.     }
  435.   while (dlen);
  436.  
  437.   return 0;
  438. }
  439.  
  440. /*
  441.  * NAME:    file->flush()
  442.  * DESCRIPTION:    flush all pending changes to an open file
  443.  */
  444. int f_flush(file)
  445.     hfsfile    *file;
  446. {
  447.   hfsvol *vol = file->vol;
  448.  
  449.   if (! (vol->flags & HFS_READONLY))
  450.     {
  451.       if (file->flags & HFS_UPDATE_CATREC)
  452.     {
  453.       node n;
  454.  
  455.       file->cat.u.fil.filStBlk   = file->cat.u.fil.filExtRec[0].xdrStABN;
  456.       file->cat.u.fil.filRStBlk  = file->cat.u.fil.filRExtRec[0].xdrStABN;
  457.       file->cat.u.fil.filClpSize = file->clump;
  458.  
  459.       if (v_catsearch(file->vol, file->parid, file->name, 0, 0, &n) <= 0 ||
  460.           v_putcatrec(&file->cat, &n) < 0)
  461.         return -1;
  462.  
  463.       file->flags &= ~HFS_UPDATE_CATREC;
  464.     }
  465.     }
  466.  
  467.   return 0;
  468. }
  469.